#include "glwidget.h"

#include "src/patch.h"
#include "src/triangle.h"
#include "src/quadrilateral.h"
#include <iostream>

#include <QtOpenGL>

namespace Ui {
	
GLWidget::GLWidget(QWidget* _parent) : QGLWidget(_parent) ,  scene(0) , shade_model(true) {
	xRot = 0;
	yRot = 0;
	zRot = 0;
}
	
GLWidget::~GLWidget(void) {
	
}
	
QSize GLWidget::minimumSizeHint(void) const {
	return QSize(50, 50);
}

QSize GLWidget::sizeHint(void) const {
	return QSize(400, 400);
}

t2c2::Radiosity* GLWidget::load_file(const char* _filename) {
	scene = input.parse(_filename);
	t2c2::Radiosity* radiosity = new t2c2::Radiosity(scene);
	updateGL();
	return radiosity;
}
	
void GLWidget::scene_opengl(void) {
	object = glGenLists(1);
	glNewList(object, GL_COMPILE);

	t2c2::Patch* patch;
	t2c2::Quadrilateral* quadrilateral = new t2c2::Quadrilateral();
	t2c2::Triangle* triangle = new t2c2::Triangle();
	for(unsigned int i = 0 ; i < scene->size_patches(); i++) {
		patch = scene->get_patch(i);
		if(typeid(*quadrilateral).name() == typeid(*patch).name()) {
			quadrilateral = static_cast<t2c2::Quadrilateral*>(patch);
			
			glBegin(GL_QUADS);
			for(unsigned int l = 0; l < 4; l++) {
				t2c2::Vector3D v = quadrilateral->get_vertex(l);
				
				t2c2::Color vertex_color(0.0,0.0,0.0);
				unsigned int m = 0;
				
				for(unsigned int j = 0 ; j < scene->size_patches(); j++) {
					t2c2::Patch* patch_;
					patch_ = scene->get_patch(i);
					if(typeid(*quadrilateral).name() == typeid(*patch_).name()) {
						t2c2::Quadrilateral* quadrilateral_ = static_cast<t2c2::Quadrilateral*>(patch_);
						for(unsigned int k = 0; k < 4; k++) {
							if(quadrilateral_->get_vertex(k) == v) {
								m++;
								vertex_color = vertex_color + quadrilateral_->get_material()->get_radiosity();
								break;
							}
						}
					}
					if(typeid(*triangle).name() == typeid(*patch_).name()) {
						t2c2::Triangle* triangle_ = static_cast<t2c2::Triangle*>(patch_);
						for(unsigned int k = 0; k < 3; k++) {
							if(triangle_->get_vertex(k) == v) {
								m++;
								vertex_color = vertex_color + triangle_->get_material()->get_radiosity();
								break;
							}
						}
					}
				}
				
				vertex_color = vertex_color*(1.0/m);
				glColor3f(vertex_color.red,vertex_color.green,vertex_color.blue);
			
				glVertex3f(v.x,v.y,v.z);	
			}
			glEnd();
		}
		else if(typeid(*triangle).name() == typeid(*patch).name()) {
			triangle = static_cast<t2c2::Triangle*>(patch);
			glBegin(GL_TRIANGLES);
				for(unsigned int l = 0; l < 3;l++) {
					t2c2::Vector3D v = triangle->get_vertex(l);
					t2c2::Color vertex_color(0.0,0.0,0.0);
					unsigned int m = 0;
				
					for(unsigned int j = 0 ; j < scene->size_patches(); j++) {
						t2c2::Patch* patch_;
						patch_ = scene->get_patch(j);
						if(typeid(*quadrilateral).name() == typeid(*patch_).name()) {
							t2c2::Quadrilateral* quadrilateral_ = static_cast<t2c2::Quadrilateral*>(patch_);
							for(unsigned int k = 0; k < 4; k++) {
								if(quadrilateral_->get_vertex(k) == v) {
									m++;
									vertex_color = vertex_color + quadrilateral_->get_material()->get_radiosity();
									break;
								}
							}
						}
						else if(typeid(*triangle).name() == typeid(*patch_).name()) {
							t2c2::Triangle* triangle_ = static_cast<t2c2::Triangle*>(patch_);
							if(triangle->get_id() == triangle_->get_id()) {
								for(unsigned int k = 0; k < 3; k++) {
									
									if(triangle_->get_vertex(k) == v) {
										m++;
									
										vertex_color = vertex_color + triangle_->get_material()->get_radiosity();
										break;
									} 
								}
							}
						}
					}
					vertex_color = vertex_color*(1.0/m);
					glColor3f(vertex_color.red,vertex_color.green,vertex_color.blue);				
					glVertex3f(v.x,v.y,v.z);
				}
			glEnd();
		}
	}
	glEndList();
}
	
bool GLWidget::get_shade_model(void) {
	return shade_model;
}
	
void GLWidget::set_shade_model(const bool _shade_model) {
	shade_model = _shade_model;
}
	
void GLWidget::initializeGL(void) {
	glClearColor(0.0,0.0,0.0,1.0);
	glEnable(GL_DEPTH_TEST);
	glShadeModel(GL_FLAT);
	//glEnable(GL_CULL_FACE);
}

void GLWidget::paintGL(void) {
	if(shade_model)
		glShadeModel(GL_FLAT);
	else 
		glShadeModel(GL_SMOOTH);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	//glTranslated(0.0, 0.0, 10.0);
	//glTranslated(0.0, 0.0, -10.0);
	

	glRotated(xRot / 16.0, 1.0, 0.0, 0.0);
	glRotated(yRot / 16.0, 0.0, 1.0, 0.0);
	glRotated(zRot / 16.0, 0.0, 0.0, 1.0);

	
	glCallList(object);
}
void GLWidget::resizeGL(int width, int height) {

	glViewport(0, 0, width, height);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if (width<=height)
		glFrustum(-5.0, 5.0, -5.0*((double)height)/width, 5.0*((double)height)/width,     5.0, 1000.0);
	else
		glFrustum(-5.0*((double)width)/height, 5.0*((double)width)/height,     -5.0, 5.0,     5.0, 1000.0);

	gluLookAt(0.0,0.0,10.0,0.0,0.0,0.0,0.0,1.0,0.0);
	glMatrixMode(GL_MODELVIEW);
}

///////////////////

void GLWidget::mouseMoveEvent(QMouseEvent *event){
	int dx = event->x() - lastPos.x();
	int dy = event->y() - lastPos.y();

	if (event->buttons() & Qt::LeftButton) {
		setXRotation(xRot + 8 * dy);
		setYRotation(yRot + 8 * dx);
	} else if (event->buttons() & Qt::RightButton) {
		setXRotation(xRot + 8 * dy);
		setZRotation(zRot + 8 * dx);
	}
	lastPos = event->pos();
}

void GLWidget::normalizeAngle(int *angle){
	while (*angle < 0)
		*angle += 360 * 16;
	while (*angle > 360 * 16)
		*angle -= 360 * 16;
}

void GLWidget::mousePressEvent(QMouseEvent *event){
	lastPos = event->pos();
}

void GLWidget::setXRotation(int angle){
	normalizeAngle(&angle);
	if (angle != xRot) {
		xRot = angle;
		emit xRotationChanged(angle);
		updateGL();
	}
}

void GLWidget::setYRotation(int angle){
	normalizeAngle(&angle);
	if (angle != yRot) {
		yRot = angle;
		emit yRotationChanged(angle);
		updateGL();
	}
}

void GLWidget::setZRotation(int angle)
{
	normalizeAngle(&angle);
	if (angle != zRot) {
		zRot = angle;
		emit zRotationChanged(angle);
		updateGL();
	}
}
}
